﻿using System;
using System.Reactive.Concurrency;
using System.Threading;
using nRoute.Utilities;
#if (!SILVERLIGHT)
using System.Threading.Tasks;
#endif

namespace nRoute.Components.Composition
{
    public class CancellableLifetimeManager
         : ILifetimeManager
    {
        private readonly Object _lock = new Object();
        private readonly CancellationToken _cancellationToken;
        private Object _instance;
        
        public CancellableLifetimeManager(CancellationToken cancellationToken)
        {
            _cancellationToken = cancellationToken;
            if (!_cancellationToken.IsCancellationRequested) cancellationToken.Register(Dispose);
        }

        public CancellableLifetimeManager(CancellationToken[] cancellationTokens)
            : this(CancellationTokenSource.CreateLinkedTokenSource(cancellationTokens).Token) { }

#region Overridable

        public Object ManageBuild(ITypeBuilder typeBuilder, Func<ITypeBuilder, object> serviceBuilder)
        {
            // not sync'ed on read?
            if (_instance == null)
            {
                lock (_lock)
                {
                    if (!_cancellationToken.IsCancellationRequested && _instance == null)
                    {
                        _instance = serviceBuilder(typeBuilder);
                    }
                }
            }

            return _instance;
        }

        protected virtual void Dispose(bool disposing) 
        {
            if (disposing)
            {
                if (_instance != null)
                {
                    lock (_lock)
                    {
                        _instance = null;
                    }
                }
            }
        }

#endregion

#region IDisposable Members

        public void Dispose()
        {
            Dispose(true);
            GC.SuppressFinalize(this);
        }

#endregion

        ~CancellableLifetimeManager() { Dispose(false); }

    }
}
